/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*   File:      MyDatabase.cpp
*   Author:    刘洋兵
*   Function:  数据库相关操作模块
*   Time:      2025-09-09
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include "MyDatabase.h"

QMutex MyDatabase::m_mutex;

/**
 * @brief  去除字符串所有空格
 * @param  str 需要去除空格的字符串
 */
void MyDatabase::remove_all_spaces(std::string &str) {
    // 使用 erase-remove 惯用法
    str.erase(std::remove(str.begin(), str.end(), ' '), str.end());
}

/**
 * @brief  MyDatabase初始化构造函数
 * @param  parent 父窗口
 */
MyDatabase::MyDatabase(QWidget* parent):
    ip("localhost"),
    port(3306),
    dbname("vehicle_dispatch_platform"),
    username("root"),
    password("000115")
{
    m_db = QSqlDatabase::addDatabase("QMYSQL", "mysql_connection");
}

/**
 * @brief  MyDatabase初始化析构函数
 */
MyDatabase::~MyDatabase() {
    // 清理所有模型
    for (auto it = m_models.begin(); it != m_models.end(); ++it) {
        delete it.value();
    }
    if(m_db.isOpen()||m_db.isValid())
    {
        m_db.close();
    }
    QSqlDatabase::removeDatabase("mysql_connection");
}

/**
 * @brief 获取MyDatabase单例实例
 * @return MyDatabase实例指针
 */
MyDatabase& MyDatabase::getInstance() {
    static MyDatabase m_instance;
    return m_instance;
}

/**
 * @brief  判断数据库连接
 * @return 是否连接成功
 */
bool MyDatabase::openDatabase()
{
    if (m_db.isOpen()) {
        return false;
    }
    // 创建数据库连接
    m_db.setHostName(ip);    // 数据库主机地址
    m_db.setPort(port);               // 端口（默认3306）
    m_db.setDatabaseName(dbname);     // 数据库名称
    m_db.setUserName(username);       // 用户名
    m_db.setPassword(password);       // 密码
    // 尝试连接
    if (!m_db.open()) {
        return true;
    }

    return false;
}

/**
 * @brief  外界修改数据库配置参数，判断新参数是否能连接数据库
 * @param  infomap 存放数据库参数的map容器
 * @return 是否连接成功
 */
bool MyDatabase::AlterDatabase(const QMap<QString, QVariant> &infomap)
{
    QMutexLocker locker(&m_mutex);
    ip = infomap["ip"].toString();
    port = infomap["port"].toInt();
    dbname = infomap["db"].toString();
    username = infomap["username"].toString();
    password = infomap["password"].toString();
    m_db.setHostName(ip);    // 数据库主机地址
    m_db.setPort(port);               // 端口（默认3306）
    m_db.setDatabaseName(dbname);     // 数据库名称
    m_db.setUserName(username);       // 用户名
    m_db.setPassword(password);       // 密码
    // 尝试连接
    if (!m_db.open()) {
        return true;
    }
    return false;
}

/**
 * @brief 关闭数据库
 */
void MyDatabase::closeDatabase()
{
    if(m_db.isOpen()||m_db.isValid())
    {
        m_db.close();
    }
}

/**
 * @brief  查询数据库表
 * @param  sql 一条完整的查询sql语句
 * @return 返回包含查询结果的数据结构dataList
 */
QList<QStringList> MyDatabase::query_table(const QString &sql)
{
    QMutexLocker locker(&m_mutex);

    QList<QStringList> dataList;
    // 执行 SQL 查询示例
    QSqlQuery query(m_db);
    if (query.exec(sql)) {
        int columnCount = query.record().count();
        while (query.next()) {
            QStringList rowData;
            for(int col=0; col < columnCount; col++){
                rowData << query.value(col).toString();
            }
            dataList.append(rowData);

        }
    } else {
        QString error = "SELECT error:" + query.lastError().text();
        LOG_ERROR(error);
        QSqlDatabase::database().rollback();
    }
    return dataList;
}

/**
 * @brief  查询数据库表
 * @param  fields 需要查询的以','为分隔符的多个表字段名
 * @param  tablename 需要查询表名
 * @return 返回包含查询结果的数据结构dataList
 */
QList<QStringList> MyDatabase::query_some_tabledata(const QString &fields, const QString &tablename, const QString &id)
{
    QMutexLocker locker(&m_mutex);

    QList<QStringList> dataList;
    QString sql = QString("select %1 from %2").arg(fields).arg(tablename);
    if(!id.isEmpty())
    {
        sql = QString("select %1 from %2 where %3").arg(fields).arg(tablename).arg(id);
    }
    // 执行 SQL 查询示例
    QSqlQuery query(m_db);
    if (query.exec(sql)) {
        int columnCount = query.record().count();
        while (query.next()) {
            QStringList rowData;
            for(int col=0; col < columnCount; col++){
                rowData << query.value(col).toString();
            }
            dataList.append(rowData);

        }
    } else {
        QString error = "SELECT error:" + query.lastError().text();
        LOG_ERROR(error);
        QSqlDatabase::database().rollback();
    }
    return dataList;
}

/**
 * @brief  判断表中主键是否已存在
 * @param  tableName 表名
 * @param  primaryKeyValue 需要判断的主键
 * @return 返回主键是否冲突
 */
bool MyDatabase::isPrimaryKeyExists(const QString &tableName, int primaryKeyValue) {
    QSqlQuery query(m_db);
    QString sql = QString("SELECT 1 FROM %1 WHERE fault_code = ?").arg(tableName);
    query.prepare(sql);
    query.addBindValue(primaryKeyValue);
    if(!query.exec()) {
        return false;
    }
    return query.next(); // 返回true表示主键已存在
}

/**
 * @brief  为每个新TableView添加对应的模型以及TableViewData结构体
 * @param  tableName 表名
 * @param  mytableData 存放sql语句、表头列表、QTableView对象指针和需添加功能按键索引的结构体
 */
void MyDatabase::addTableMonitor(const QString &tableName, TableViewData &mytableData)
{
    // 检查是否已经监视该表
    if (m_models.contains(tableName)) {
        //if(m_tableWidgets[tableName].table)
        for (auto it = m_tableWidgets.begin(); it != m_tableWidgets.end(); ++it) {
            if (it.value().table == mytableData.table) {
                refreshTable(tableName);
                return;
            }
        }
    }
    QString sql = mytableData.sql;
    QList<QStringList> dataList = MyDatabase::getInstance().query_table(sql);
    int rowcount = dataList.count();
    int colcount = mytableData.HeaderList.count();
    // 创建并配置模型
    QStandardItemModel *model = new QStandardItemModel(rowcount,colcount);
    if (model == nullptr) {
        delete model;
        return;
    }
    // 设置model表头
    model->setHorizontalHeaderLabels(mytableData.HeaderList);
    // 设置QTableView基本属性
    mytableData.table->setModel(model);
    mytableData.table->verticalHeader()->setDefaultSectionSize(40);
    mytableData.table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);  //水平分布
    mytableData.table->setAlternatingRowColors(true);
    mytableData.table->setEditTriggers(QAbstractItemView::SelectedClicked );
    mytableData.table->setColumnHidden(0,true);

    // 添加模型赋值
    tableDataRefresh(model,mytableData,rowcount,colcount,dataList);

    // 在最后一列添加功能按键
    emit setButton(model, mytableData.table, mytableData.IconNum, model->rowCount());

    // 定时操作
    QTimer* m_refreshTimer = new QTimer(this);
    connect(m_refreshTimer, &QTimer::timeout, this, [=]{
        this->refreshTable(tableName);
    });

    // 连接数据变化信号
    //connect(model, &QStandardItemModel::dataChanged, this, &MyDatabase::onModelDataChanged);

    // 存储模型和对应的tableView数据结构体
    m_models[tableName] = model;
    m_tableWidgets[tableName] = mytableData;
    m_refreshTimers[tableName] = m_refreshTimer;
}

/**
 * @brief  QStandardItemModel模型数据变动时触发的槽函数
 */
void MyDatabase::onModelDataChanged(const QModelIndex &topLeft,
                                    const QModelIndex &bottomRight,
                                    const QVector<int> &roles)
{
    Q_UNUSED(roles);

   // 找出是哪个模型发出的信号
   QStandardItemModel *model = qobject_cast<QStandardItemModel*>(sender());
   if (!model) return;

   // 找出对应的表名
   QString tableName;
   for (auto it = m_models.begin(); it != m_models.end(); ++it) {
       if (it.value() == model) {
           tableName = it.key();
           break;
       }
   }
   if (tableName.isEmpty()) return;

   // 更新对应的tableWidget
   QTableView *tableView = m_tableWidgets[tableName].table;
   if (tableView) {
       updateTableWidget(tableView, model);
   }
   // 发出通知信号
   emit tableDataChanged(tableName);

}

/**
 * @brief  为每个新TableView添加对应的模型以及TableViewData结构体
 * @param  tableView 控件tableView对象指针
 * @param  model 模型QStandardItemModel对象指针
 */
void MyDatabase::updateTableWidget(QTableView *tableView, QStandardItemModel *model, const QString& new_sql)
{
    if (!tableView || !model) return;
    // 暂停信号发射以提高性能
    tableView->blockSignals(true);

    // 找到model对应的表名
    QString tableName;
    for (auto it = m_models.begin(); it != m_models.end(); ++it) {
        if (it.value() == model) {
            tableName = it.key();
            break;
        }
    }
    TableViewData mytableData = m_tableWidgets[tableName];
    // 设置表头
    QStringList headers;
    model->setHorizontalHeaderLabels(mytableData.HeaderList);
    // 老模型的行数
    int oldrowCount = model->rowCount();
    // 填充数据
    QString sql = mytableData.sql;
    if(!new_sql.isEmpty())
    {
        // 通过新sql查询数据
        sql = new_sql;
    }
    QList<QStringList> dataList = MyDatabase::getInstance().query_table(sql);
    int rowcount = dataList.count();
    int colcount = mytableData.HeaderList.count();
    // 设置模型新的行数
    model->setRowCount(rowcount);

    // 更新model数据
    tableDataRefresh(model,mytableData,rowcount,colcount,dataList);

    // 判断刷新的数据行数来执行添加按键或者删除行
    if(rowcount > oldrowCount)
    {
        // 如果刷新时数据库表的行数大于模型中的行数，就添加新的按键单元格
        int updatenum = rowcount - oldrowCount;
        emit setButton(model, tableView, mytableData.IconNum, updatenum);
    }else if(rowcount < oldrowCount){
        // 如果刷新时新数据的函数少于老模型的行数，删除老模型多余的行数据
        int updatenum = oldrowCount - rowcount;
        for (int i = updatenum-1; i >= 0; i--) {
            model->removeRow(rowcount + i);
        }
    }
    // 恢复信号发射
    tableView->blockSignals(false);
}

/**
 * @brief  对model模型更新数据
 * @param  model QStandardItemModel模型对象指针
 * @param  mytableData 存放sql语句、表头列表、QTableView对象指针和需添加功能按键索引的结构体
 * @param  rowcount 表格行数
 * @param  colcount 表格列数
 * @param  dataList 存放数据库表读取的数据列表
 */
void MyDatabase::tableDataRefresh(QStandardItemModel *model,
                                  const TableViewData &mytableData,
                                  const int &rowcount,
                                  const int &colcount,
                                  const QList<QStringList> &dataList)
{
    for(int row = 0; row < rowcount; row++) {
        // 判断是否有特定列数据需要代替显示
        if(mytableData.is_true)
        {
            for (int col = 0; col < colcount-1; col++) {

                QModelIndex index = model->index(row, col);
                model->setData(index,dataList[row][col]);
                model->setData(index, Qt::AlignCenter, Qt::TextAlignmentRole);
            }
        }else {
            for (int col = 0; col < colcount-1; col++) {
                QModelIndex index = model->index(row, col);
                // 数据显示类型
                int dataType = dataList[row][col].toInt();
                QString header = mytableData.HeaderList[col];
                CellDataFormat cellData;

                switch (mytableData.cellDataFormat[mytableData.HeaderList[col]]) {
                    case CellType::OTHER:
                    {
                        model->setData(index,dataList[row][col]);
                        model->setData(index, Qt::AlignCenter, Qt::TextAlignmentRole);
                        break;
                    }
                    case CellType::STRING_DATA:
                    {
                        QString data = cellData.setDataCell(mytableData.table,mytableData.HeaderList[col],dataType);
                        model->setData(index, data);
                        model->setData(index, Qt::AlignCenter, Qt::TextAlignmentRole);
                        break;
                    }
                    case CellType::ICON:
                    {
                        // 对于只有0或1选项的设计
                        QWidget *widget = new QWidget(this);
                        if(dataType)
                        {
                            QHBoxLayout* vLay = new QHBoxLayout(widget);
                            QLabel *imageLabel = new QLabel(widget);
                            QPixmap pix(":/Icon/image/is_running.png");
                            imageLabel->setPixmap(pix.scaled(25, 25, Qt::KeepAspectRatio)); 
                            vLay->addWidget(imageLabel);
                            vLay->setAlignment(Qt::AlignCenter);
                            vLay->setContentsMargins(0,0,0,0);
                            widget->setLayout(vLay);
                        }
                        mytableData.table->setIndexWidget(model->index(row, 9), widget);
                        break;
                    }
                }
            }
        }
    }
}

/**
 * @brief  刷新某张表数据
 * @param  tableName 表名
 */
void MyDatabase::refreshTable(const QString &tableName, const QString& new_sql)
{
    if (m_models.contains(tableName)) {

        QTableView *tableView = m_tableWidgets.value(tableName).table;
        if (tableView) {
            updateTableWidget(tableView, m_models[tableName], new_sql);
        }
    }
}

/**
 * @brief  赛选显示表数据
 * @param  data 需要显示的行
 * @param  tableName 表名
 */
void MyDatabase::setProxy(QMap<int,bool> &data, QString tablenanme)
{
    auto &tableView = m_tableWidgets[tablenanme].table;
    if(!tableView || !m_models[tablenanme])
    {
        return;
    }
    tableView->blockSignals(true);
    // 显示所有行
    for(int i=0; i < m_models[tablenanme]->rowCount(); ++i)
        m_tableWidgets[tablenanme].table->setRowHidden(i, true);

    for (auto it = data.begin(); it != data.end(); ++it) {
        if(it.value())
        {
            m_tableWidgets[tablenanme].table->setRowHidden(it.key(), false);
        }

    }

    tableView->blockSignals(false);
}

// 开启1秒一次的定时器
void MyDatabase::startTimer(const QString &tableName)
{
    m_refreshTimers[tableName]->start(1000);
}

// 关闭定时器
void MyDatabase::stopTimer(const QString &tableName)
{
    m_refreshTimers[tableName]->stop();
}






